// Copyright (c) 2018-2019,  Jiang Si. For more information see 'LICENSE'
#pragma once

#include "Interface/IWindow.h"
#include "Meleon/Vulkan/Create/VulkanDeviceExt.h"
#include "Meleon/Meleon.h"
#include "GSStl/Algorithms/StringUtils.h"

namespace GS
{

	//
	// Frame Graph Test Application
	//

	class GSApp final : public IWindowEventListener
	{
		// types
	private:
		using TestFunc_t = bool (GSApp::*) ();
		using TestQueue_t = Deque<Pair< TestFunc_t, uint >>;
		using DebugReport = VulkanDeviceExt::DebugReport;
		using IPipelineCompilerPtr = SharedPtr< class IPipelineCompiler >;


		// variables
	private:
		WindowPtr				_window{nullptr};
		IPipelineCompilerPtr	_pplnCompiler{nullptr};
		SwapchainID				_swapchainId;
		GPipelineID				_gPipelineId;

		IMeleon*				_pMeleon;
		FrameGraph				_frameGraph;
		TestQueue_t				_tests;
		uint					_testInvocations = 0;
		uint					_testsPassed = 0;
		uint					_testsFailed = 0;
		uint					_frameID = 0;


		// methods
	public:
		GSApp();
		~GSApp();

		virtual bool DrawScene() { return false; }
		static void Run();


		// IWindowEventListener
	private:
		void OnResize(const uint2 &size) override;
		void OnRefresh() override {}
		void OnDestroy() override {}
		void OnUpdate() override;
		void OnKey(StringView, EKeyAction) override {}
		void OnMouseMove(const float2 &) override {}


		// helpers
	private:
		bool _Initialize(WindowPtr &&wnd);
		bool _CreateGraphicPipeline();
		bool _MainLoop();
		bool _Update();
		void _Destroy();

		bool Visualize(StringView name) const;
		bool CompareDumps(StringView filename) const;
		bool SavePNG(const String &filename, const ImageView &imageData) const;

		template <typename ...Args>
		void DeleteResources(Args& ...args);

		template <typename Arg0, typename ...Args>
		void _RecursiveDeleteResources(Arg0 &arg0, Args& ...args);

		ND_ Array<uint8_t>	CreateData(BytesU size) const;

		ND_ static String  GetFuncName(StringView src);
	};


	template <typename ...Args>
	inline void GSApp::DeleteResources(Args& ...args)
	{
		_RecursiveDeleteResources(std::forward<Args&>(args)...);
	}


	template <typename Arg0, typename ...Args>
	inline void  GSApp::_RecursiveDeleteResources(Arg0 &arg0, Args& ...args)
	{
		_frameGraph->ReleaseResource(INOUT arg0);

		if constexpr (CountOf<Args...>())
			_RecursiveDeleteResources(std::forward<Args&>(args)...);
	}


	inline String  GSApp::GetFuncName(StringView src)
	{
		size_t	pos = src.find_last_of("::");

		if (pos != StringView::npos)
			return String{ src.substr(pos + 1) };
		else
			return String{ src };
	}

#	define TEST_NAME	GetFuncName( FG_FUNCTION_NAME )


}	// GS
